package com.common.lib.network

import com.common.lib.bean.*
import com.common.lib.constant.Constants
import com.common.lib.manager.DataManager
import com.common.lib.utils.LogUtil
import com.google.gson.GsonBuilder
import hu.akarnokd.rxjava3.retrofit.RxJava3CallAdapterFactory
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Observer
import io.reactivex.rxjava3.schedulers.Schedulers
import me.jessyan.retrofiturlmanager.RetrofitUrlManager
import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.IOException
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException


class HttpMethods private constructor() {

    private val TAG: String = "HttpMethods"

    private val api: Api

    private var mRetrofit: Retrofit? = null
    private val mBuilder: OkHttpClient.Builder

    public var sType: String = "2"

    companion object {
        const val TAG = "HttpMethods"
        const val CONNECT_TIMEOUT: Long = 90
        const val WRITE_TIMEOUT: Long = 90
        const val READ_TIMEOUT: Long = 90

        @Volatile
        private var instance: HttpMethods? = null

        fun getInstance() =
            instance
                ?: synchronized(this) {
                    instance
                        ?: HttpMethods()
                            .also { instance = it }
                }
    }

    init {
        val okHttpClient = RetrofitUrlManager.getInstance().with(OkHttpClient.Builder()).build()
        mBuilder = okHttpClient.newBuilder()
        val loggingInterceptor =
            HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
                override fun log(message: String) {
                    LogUtil.LogE(message)
                }
            })
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)


        val interceptor: Interceptor = object : Interceptor {
            @Throws(IOException::class)
            override fun intercept(chain: Interceptor.Chain): Response {
                val builder = chain.request()
                    .newBuilder()
//                val token = DataManager.getInstance().getToken()
//                if (!TextUtils.isEmpty(token)) {
//                    builder.addHeader("Authorization", token!!)
//                }
//                builder.addHeader(
//                    "Accept-Language",
//                    if (DataManager.getInstance().getLanguage() == 0) {
//                        "en-us"
//                    } else {
//                        "zh-cn"
//                    }
//                )
//                builder.addHeader("Platform", "APP_ANDROID")
                return chain.proceed(builder.build())
            }
        }
        mBuilder
            .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
            .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
            .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
            .addInterceptor(interceptor)
            .addInterceptor(loggingInterceptor)
        resetRetrofit()
        api = mRetrofit!!.create(Api::class.java)
    }

    fun resetRetrofit() {
        val url: String
        url = if (DataManager.getInstance().getRegion() == 0) {
            "https://www.thinkfiter.com"
        } else {
            "https://en.thinkfiter.com"
        }
        mRetrofit = Retrofit.Builder()
            .client(mBuilder.build())
            .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create()))
            .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
            .baseUrl(url)//
            .build()
    }

    fun sendCode(
        phone: String,
        observer: HttpObserver<BasicResponse<Any>, Any>
    ) {
        val map = getMap()
        map["phone"] = phone
        val observable = api.sendCode(map)
        toSubscribe(observable, observer)
    }

    fun telLogin(
        phone: String,
        code: String,
        observer: HttpObserver<BasicResponse<UserBean>, UserBean>
    ) {
        val map = getMap()
        map["phone"] = phone
        map["dxcode"] = code
        val observable = api.telLogin(map)
        toSubscribe(observable, observer)
    }

    fun wxLogin(
        unionid: String,
        openid: String,
        observer: HttpObserver<BasicResponse<UserBean>, UserBean>
    ) {
        val map = getMap()
        map["unionid"] = unionid
        map["openid"] = openid
        val observable = api.wxLogin(map)
        toSubscribe(observable, observer)
    }

    fun getUserInfo(
        uid: String,
        observer: HttpObserver<BasicResponse<UserBean>, UserBean>
    ) {
        val map = getMap()
        map["uid"] = uid
        val observable = api.getUserInfo(map)
        toSubscribe(observable, observer)
    }

    fun editUser(
        uid: String,
        key: String,
        value: String,
        observer: HttpObserver<BasicResponse<Any>, Any>
    ) {
        val map = getMap()
        map[key] = value
        map["uid"] = uid
        val observable = api.editUser(map)
        toSubscribe(observable, observer)
    }

    fun videoList(
        uid: String,
        stype: Int,
        type: Int,
        minTime: Int,
        maxTime: Int,
        vtagid: Int,
        star: Int,
        iscollect: Int,
        page: Int,
        observer: HttpObserver<BasicResponse<ArrayList<VideoBean>>, ArrayList<VideoBean>>
    ) {
        val map = getMap()
        map["vip"] = 0
        map["stype"] = stype
        map["type"] = type
        map["uid"] = uid
        map["minTime"] = minTime
        map["maxTime"] = maxTime
        map["vtagid"] = vtagid
        map["star"] = star
        map["iscollect"] = iscollect
        map["page"] = page
        val observable = api.videoList(map)
        toSubscribe(observable, observer)
    }
    fun videoTag(
        stype: Int,
        observer: HttpObserver<BasicResponse<ArrayList<VideoTagBean>>, ArrayList<VideoTagBean>>
    ) {
        val map = getMap()
        map["brandid"] = Constants.BRANDID
        map["stype"] = stype
        val observable = api.getVideoTag(map)
        toSubscribe(observable, observer)
    }
    fun addcollect(
        stype: Int,
        vid: Int,
        uid: String,
        type: Int,
        observer: HttpObserver<BasicResponse<Any?>, Any?>
    ) {
        val map = getMap()
        map["brandid"] = Constants.BRANDID
        map["stype"] = stype
        map["vid"] = vid
        map["uid"] = uid
        map["type"] = type
        val observable = api.addcollect(map)
        toSubscribe(observable, observer)
    }

    fun videoDetail(
        uid: String,
        type: Int,
        vid: Int,
        observer: HttpObserver<BasicResponse<VideoBean>, VideoBean>
    ) {
        val map = getMap()
        map["vtype"] = type
        map["uid"] = uid
        map["vid"] = vid
        val observable = api.videoDetail(map)
        toSubscribe(observable, observer)
    }

    fun videoInfo(
        uid: String,
        type: Int,
        vid: Int,
        observer: HttpObserver<BasicResponse<VideoBean>, VideoBean>
    ) {
        val map = getMap()
        map["brandid"] = Constants.BRANDID
        map["vtype"] = type
        map["uid"] = uid
        map["vid"] = vid
        val observable = api.videoInfo(map)
        toSubscribe(observable, observer)
    }

    fun getTVData(
        observer: HttpObserver<BasicResponse<ArrayList<VideoBean>>, ArrayList<VideoBean>>
    ) {
        val observable = api.getTVData()
        toSubscribe(observable, observer)
    }

    fun getAdvert(
        cid: Int,
        observer: HttpObserver<BasicResponse<ArrayList<BannerBean>>, ArrayList<BannerBean>>
    ) {
        val map = getMap()
        map["cid"] = cid
        map["appid"] = 6
        val observable = api.getAdvert(map)
        toSubscribe(observable, observer)
    }

    fun getSportRecord(
        uid: String,
        page: Int,
        observer: HttpObserver<BasicResponse<ArrayList<SportRecordBean>>, ArrayList<SportRecordBean>>
    ) {
        val map = getMap()
        map["uid"] = uid
        map["page"] = page
        val observable = api.getSportRecord(map)
        toSubscribe(observable, observer)
    }

    fun getSportInfo(
        uid: String,
        observer: HttpObserver<BasicResponse<SportInfoBean>, SportInfoBean>
    ) {
        val map = getMap()
        map["uid"] = uid
        val observable = api.getSportInfo(map)
        toSubscribe(observable, observer)
    }

    fun getVideoRecord(
        uid: String,
        page: Int,
        observer: HttpObserver<BasicResponse<ArrayList<VideoBean>>, ArrayList<VideoBean>>
    ) {
        val map = getMap()
        map["uid"] = uid
        map["page"] = page
        val observable = api.getVideoRecord(map)
        toSubscribe(observable, observer)
    }

    fun addVideoRecord(
        uid: String,
        vid: Int,
        type: Int,
        observer: HttpObserver<BasicResponse<Any>, Any>
    ) {
        val map = getMap()
        map["uid"] = uid
        map["vid"] = vid
        map["type"] = type
        val observable = api.addVideoRecord(map)
        toSubscribe(observable, observer)
    }

    fun checkVer(
        verno: Int,
        appid: Int,
        observer: HttpObserver<BasicResponse<VersionBean>, VersionBean>
    ) {
        val map = getMap()
        map["verno"] = verno
        map["appid"] = appid
        val observable = api.checkVer(map)
        toSubscribe(observable, observer)
    }

    fun runUploadSportInfo(
        uid: String,
        rid: Int,
        type: Int,
        distance: String,
        watts: String,
        rpm: String,
        bpm: String,
        kj: String,
        kcal: String,
        times: Int,
        detail: String,
        isend: Int,
        observer: Observer<BasicResponse<Any?>>
    ) {
        val map = getMap()
        map["uid"] = uid
        map["rid"] = rid
        map["type"] = type
        map["distance"] = distance
        map["watts"] = watts
        map["rpm"] = rpm
        map["bpm"] = bpm
        map["kj"] = kj
        map["kcal"] = kcal
        map["times"] = times
        map["detail"] = detail
        map["isend"] = isend
        val observable = api.runUploadSportInfo(map)
        toSubscribe2(observable, observer)
    }

    fun uploadSportInfo(
        uid: String,
        rid: Int,
        vid: Int,
        type: Int,
        score: Int,
        mateid: Int,
        distance: String,
        watts: String,
        rpm: String,
        bpm: String,
        kj: String,
        kcal: String,
        times: Int,
        detail: String,
        isend: Int,
        observer: Observer<BasicResponse<Any?>>
    ) {
        val map = getMap()
        map["uid"] = uid
        map["rid"] = rid
        map["vid"] = vid
        map["mateid"] = mateid
        map["type"] = type
        map["distance"] = distance
        map["watts"] = watts
        map["rpm"] = rpm
        map["bpm"] = bpm
        map["kj"] = kj
        map["kcal"] = kcal
        map["times"] = times
        map["detail"] = detail
        map["isend"] = isend
        map["score"] = score
        val observable = api.uploadinfo(map)
        toSubscribe2(observable, observer)
    }


    fun randomUser(
        uid: String,
        vid: Int,
        type: Int,
        observer: Observer<BasicResponse<Any?>>
    ) {
        val map = getMap()
        map["uid"] = uid
        map["vid"] = vid
        map["type"] = type
        val observable = api.randomUser(map)
        toSubscribe2(observable, observer)
    }

    fun brandInfo(observer : HttpObserver<BasicResponse<BrandInfoBean>,BrandInfoBean>){
        val map = getMap();
        map["brandid"] = Constants.BRANDID
        val observable = api.brandInfo(map)
        toSubscribe(observable,observer)
    }


    fun getApkList(
        observer: HttpObserver<BasicResponse<ArrayList<ApplicationBean>>, ArrayList<ApplicationBean>>
    ) {
        val map = getMap()
        map["aid"] = 6
        val observable = api.getApkList(map)
        toSubscribe(observable, observer)
    }

    fun getVideoList(
        stype: Int,
        tid: Int,
        minTime: Int,
        maxTime: Int,
        brandid: Int,
        observer: HttpObserver<BasicResponse<ProceduralTrainBean>, ProceduralTrainBean>
    ){
        val map = getMap()
        map["stype"] = stype
        map["tid"] = tid
        map["minTime"] = minTime
        map["maxTime"] = maxTime
        map["brandid"] = brandid
        val observable = api.getVideoList(map)
        toSubscribe(observable,observer)
    }
    fun getWattinfo(
        vid: Int,
        observer: HttpObserver<BasicResponse<VideoInfoBean>, VideoInfoBean>
    ){
        val map = getMap()
        map["vid"] = vid
        val observable = api.getWattinfo(map)
        toSubscribe(observable,observer)
    }
    fun recordDetail(
        rid: Int,
        langId: Int,
        observer: HttpObserver<BasicResponse<RecordDetailBean>, RecordDetailBean>
    ){
        val map = getMap()
        map["rid"] = rid
        map["langId"] = langId
        val observable = api.recordDetail(map)
        toSubscribe(observable,observer)
    }


    fun getMap(): HashMap<String, Any> {
        val map = HashMap<String, Any>()
        val loginData = null
        //		HashMap<String, String> versionNameInfo = SPConfig.getInstance(context).getVersionNameInfo();
        map["brandid"] = Constants.BRANDID
        map["stype"] = sType
        map["languageId"] = if (DataManager.getInstance().getLanguage() == 1) 1 else 0
        map["deviceid"] = Constants.DEVICEID
//        if (loginData != null) {
//            map["uid"] = loginData.getUid()
//            map["cptoken"] = loginData.getCptoken()
//        }
        return map
    }




    private fun <T : BasicResponse<Data>, Data> toSubscribe(
        observable: Observable<T>,
        observer: HttpObserver<T, Data>
    ) {
        observable.retry(2) { throwable ->
            throwable is SocketTimeoutException ||
                    throwable is ConnectException ||
                    throwable is TimeoutException
        }.subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(observer)
    }

    private fun toSubscribe2(
        observable: Observable<BasicResponse<Any?>>,
        observer: Observer<BasicResponse<Any?>>
    ) {
        observable.retry(2) { throwable ->
            throwable is SocketTimeoutException ||
                    throwable is ConnectException ||
                    throwable is TimeoutException
        }.subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(observer)
    }


}
